iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0
Software Development

文藝復興:這段程式碼,好像有點味道系列 第 21

Day 21|領了畫布錢,卻什麼都沒畫的學徒:懶惰的類別 (Lazy Class)

  • 分享至 

  • xImage
  •  

畫室養一位學徒,是有成本的

要給他一個位置、分他畫布跟顏料、師傅要花時間指導他

如果這位學徒,每天只做一件早就可以交給別人順手完成的小事
畫室養著他的成本,早就超過他能貢獻的價值

不是他做錯了什麼,是他存在的理由,已經站不住腳了

重構後,留下了一個瘦到只剩一行的類別

回頭看 Day 16

當時為了解決霰彈式修改,我們把散落在三個服務裡的驗證邏輯,集中回 OrderRequest.Validate()

但在那次重構之前,其實還有一段更早的歷史
專案一開始,是先建立了一個 OrderValidationHelper 類別,把驗證邏輯包在裡面

public class OrderValidationHelper
{
    public void EnsureValid(OrderRequest request)
    {
        request.Validate();
    }
}

三個服務,仍然照著舊習慣呼叫它:

public class OrderProcessor
{
    private readonly OrderValidationHelper _validationHelper;

    public decimal Process(OrderRequest request)
    {
        _validationHelper.EnsureValid(request);
        // ...原有處理邏輯...
        return 0;
    }
}

這位學徒,只剩下轉手一件事

打開 OrderValidationHelper它只做一件事:把呼叫轉給 request.Validate()
自己什麼邏輯都沒有

  • 它沒有自己的資料
  • 它沒有自己的規則
  • 它存在的唯一理由,是 「歷史共業」

Day 16 重構的時候,我們把驗證邏輯「物歸原主」搬回了 OrderRequest,卻忘了回頭看一眼
那個原本裝著邏輯的舊房子,現在已經空了,只剩一具空殼站在那裡

三個服務,還在依賴注入裡多帶著一個 OrderValidationHelper
每個人讀到這裡,都要多花幾秒鐘搞懂:「這一層轉傳,是必要的嗎?」

答案是,不必要

把空殼收起來

解法很直接,是內聯類別 (Inline Class):把 OrderValidationHelper 僅剩的呼叫,直接攤平回呼叫端

public class OrderProcessor
{
    public decimal Process(OrderRequest request)
    {
        request.Validate();
        // ...原有處理邏輯...
        return 0;
    }
}

public class OrderImportService
{
    public void Import(OrderRequest request)
    {
        request.Validate();
        // ...匯入邏輯...
    }
}

public class OrderEditService
{
    public void Edit(OrderRequest request)
    {
        request.Validate();
        // ...編輯邏輯...
    }
}

OrderValidationHelper 整個類別,可以安全刪除

三個服務的建構子也跟著變輕,少了一個完全不需要注入的相依物件

懶惰的類別,通常不是設計出來的

今天的例子,是重構後的殘留物

這其實是懶惰類別最常見的成因,不是有人故意設計了一個「懶惰」的類別
是它原本很稱職,只是後來職責被搬空了

另一種常見成因,是「為未來預留」(這也是筆者我最常犯的問題):

// 為了「以後可能要串第三方物流商」而先建的殼
public class ShippingProviderAdapter
{
    public void Ship(Order order) => Console.WriteLine("出貨");
}

如果那個「以後」始終沒有到來,這個類別的處境,跟今天的 OrderValidationHelper 一樣
佔著一個位置,卻交不出對得起這個位置的產出

怎麼判斷,該不該留

不是所有小類別都該被刪掉,判斷的重點是:

  • 這個類別,能不能用一句話說清楚它存在的必要性?
  • 它的職責,是不是已經被其他地方吸收,只剩下空殼轉傳
  • 如果把它內聯進呼叫端,呼叫端會不會反而變得難以理解?如果會,代表它其實還有存在的價值

懶惰的類別不是「小」的問題,是「小到配不上它佔用的維護成本」的問題

自我檢查清單

  1. 這個類別,我能用一句話說清楚它存在的必要性嗎?
  2. 它的公開方法,是不是只剩下一兩個,而且邏輯薄弱?
  3. 這個類別,是不是重構後留下的殘留物,職責早就被搬去別的地方?
  4. 如果把它刪掉、內聯進呼叫端,程式碼會變得更難懂,還是更清楚?
  5. 這個類別,是不是「為了以後可能用到」而預先建立,但那個以後始終沒有來?

明日預告

明天我們看另一種極端:一個類別,只會被人擠資料、自己什麼行為都不做

模組四第四站:純資料類別(Data Class)


上一篇
Day 20|同一張草稿,抄了五份放在不同抽屜:重複的程式碼 (Duplicate Code)
下一篇
Day 22|只會被人擠顏料,自己不會調色的調色盤:純資料類別 (Data Class)
系列文
文藝復興:這段程式碼,好像有點味道27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言